using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

namespace shaco
{
    public class HyridCLRHelper
    {
        class LoadAOTInfo
        {
            public string aotDllName;
            public YooAsset.AssetHandle handle;
            public byte[] dllBytes;
        }

        static void RunThread(System.Action callbackInvoke)
        {
#if UNITY_WEBGL
            RunSafeCallback(callbackInvoke);
#else
            System.Threading.ThreadPool.QueueUserWorkItem((object value) =>
            {
                callbackInvoke();
            });
#endif
        }

        static public IEnumerator LoadDll(IEnumerable<string> dllNames, string packageName, string prefixPath, string logTag, System.Action<string, byte[]> callbackLoadInThread)
        {
            var package = YooAsset.YooAssets.GetPackage(packageName);
            var dllNameCount = dllNames.Count();
            var loadDllHandle = new LoadAOTInfo[dllNameCount];
            var isLoadEnd = false;
            var loadingProgress = 0f;
            var threadTimeout = 60f;

            HyridCLRHelper.RunThread(() =>
            {
                Debug.Log("LoadDllDataBase threa start..." + logTag);
                try
                {
                    var timeTest2 = System.DateTime.Now;
                    var loadedIndex = 0;

                    while (true)
                    {
                        System.Threading.Thread.Sleep(10);
                        threadTimeout -= 0.01f;
                        if (threadTimeout <= 0)
                        {
                            Debug.LogError($"子线程加载{logTag}超时");
                            break;
                        }

                        LoadAOTInfo loadedInfo = null;
                        lock (loadDllHandle)
                        {
                            for (int i = 0; i < loadDllHandle.Length; ++i)
                            {
                                if (null != loadDllHandle[i])
                                {
                                    loadedInfo = loadDllHandle[i];
                                    loadDllHandle[i] = null;
                                    break;
                                }
                            }
                        }

                        //读取和加载都完毕了
                        if (isLoadEnd && null == loadedInfo)
                            break;

                        //等待读取数据中
                        if (null == loadedInfo)
                            continue;

                        var aotDllName = loadedInfo.aotDllName;
                        var dllBytes = loadedInfo.dllBytes;
                        callbackLoadInThread(aotDllName, dllBytes);
                        loadedInfo.handle.Release();

                        ++loadedIndex;
                        loadingProgress = (float)loadedIndex / dllNameCount;
                    }
                    Debug.Log($"子线程加载{logTag}耗时====" + (System.DateTime.Now - timeTest2).TotalSeconds);
                }
                catch (System.Exception e)
                {
                    throw new System.Exception($"子线程加载{logTag}发生错误, e=" + e);
                }
            });

            var timeTest1 = System.DateTime.Now;
            var index = 0;
            foreach (var iter in dllNames)
            {
                var aotDllName = iter;
                var loadRequest = package.LoadAssetAsync<TextAsset>($"{prefixPath}/{aotDllName}.bytes");
                yield return loadRequest;

                if (loadRequest.Status == YooAsset.EOperationStatus.Failed)
                {
                    Debug.LogError($"加载dll发生错误, name:{aotDllName} status:{loadRequest.Status} error:{loadRequest.LastError}");
                    continue;
                }

                lock (loadDllHandle)
                {
                    loadDllHandle[index++] = new()
                    {
                        aotDllName = aotDllName,
                        handle = loadRequest,
                        dllBytes = (loadRequest.AssetObject as TextAsset).bytes
                    };
                }
            }
            isLoadEnd = true;
            Debug.Log($"其他协程读取{logTag}耗时====" + (System.DateTime.Now - timeTest1).TotalSeconds);

            while (loadingProgress < 1)
                yield return null;
        }
    }
}
